home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
326-350
/
disk_330
/
xprkermit
/
kermitproto.doc
< prev
next >
Wrap
Text File
|
1992-05-06
|
9KB
|
226 lines
The Small Portable Kermit Module (kermitproto.w)
Stephen Walton
August 2, 1988
The attached set of routines, which I have christened "kermitproto.w",
represent several weeks of work. It is intended to be a single,
self-contained set of Kermit protocol routines suitable for adding to
a microcomputer terminal emulation program. As such, it does not
allow the microcomputer to act as a server. It does provide long
packets, client support, and the optional protocol for a clean
interrupt.
The code began its life as the routines in the book _Kermit: A File
Transfer Protocol_ by Frank da Cruz (Digital Press, 1986). I have kept
the original style of the book's code, only fixing bugs and adding
some Lint-related items. I must say here that I don't care all that
much for the code in the book. The C language provides many more
elegant constructs for doing what Kermit requires. Far too many
important flags and result returns are done via global variables. Not
a single instance of pointers to functions, enums, structs, macros
beyond very simple string replacement, or abstract data types is to be
found herein. These should not be used for their own sake, but it
seems to me that they could make Kermit code much easier to read. An
ADT called "packet" is an obvious possibility.
The code communicates to the outside world through both some
subroutines which the user must provide and a set of global variables
which control some aspects of the protocol. The variables can safely
be ignored for the most part; they start out with reasonable default
values which are modified as the result of Kermit transactions. Only
3 must be set by the user interface, and my module declares these as
extern so your code won't link if you don't.
File Handling Primitives
The module contains file handling primitives written in terms of the
soon-to-be ANSI standard I/O library. These ought to work on nearly
all systems, though some (MS-DOS for one) may require some changes to
distinguish between text and binary files. The ones most likely to
require local changes are zltor() and zrtol() for converting file
names back and forth between the local format and the generic Kermit
format.
Serial Port Primitives
The first set of user-provided routines are for handling the
serial communications.
int ttol(char *out_string, int n)
Writes the n characters beginning at outstring to the serial port
using the current settings of flow control, parity, word length, etc.
Returns the number of characters read from the port or -1 on failure.
int ttinl(char *in_string, int max, int timeout, int eol)
Reads characters from the serial port into in_string. It stops when
either max characters have been seen or the end-of-read marker eol has
been seen. If timeout is greater than 0, then the read must be
completed in no more than timeout seconds. The value returned is the
number of characters actually read or -1 on error or timeout.
void ttflui(void)
Removes all pending readable characters from the serial port.
Other User-Provided Routines
int gnfile(char *filename, int length)
Copies the next file for Kermit to SEND or GET into the character
string pointed to by filename, of maximum length length. Returns a
positive flag if there is a next file, 0 or negative if not.
void sleep(int seconds)
Pause the user's program for the given number of seconds.
Status Routines
These routines are used to report the status of the protocol to
the user's program for possible display.
void tchar(char c)
Place the character "c" on the user's terminal. c is a . for a
successful packet transfer and a % for a retry, but c can also be
anything a remote server might send in response to client commands
(REMOTE COMMAND, for example).
void tmsg(char *message)
Write the null-terminated string without a carriage return; i.e., if I
call tmsg("first ") and tmsg("word"), the user should see "first word"
displayed.
void tmsgl(char *message)
Write tne null-terminated string and start a new line after
displaying.
Future update plans call for adding code to count packets, file
bytes, and naks and adding a special call for displaying this type of
information, similar to the screen() routine in C Kermit 4E(070).
Starting It Up
All Kermit protocol transfers are started by doing whatever startup
the user's code requires, putting the appropriate start state into the
extern int start, and calling the routine proto(). Here are the supported
start states and how they work:
'v': Receive a file. The protocol module assumes that the remote Kermit
has been given a SEND command, and passively waits (with timeouts) for the
file(s) to start arriving. Your Kermit receive subroutine could be as
simple as:
void kermit_receive(void)
{
extern int start;
start = 'v';
proto();
}
's': Send a file. The protocol module calls gnfile() (see above)
repeatedly, and sends each file requested to the remote. The remote must
have been given a RECEIVE or a SERVER command first.
'r': Get file(s). The protocol module calls gnfile() for a list of files
to request from a remote Kermit server. These can generally include
wildcards in the remote's syntax, for example *.FOR for all Fortran files
from an MS/DOS server or *.c for all C files from a Unix server.
'g': Kermit generic commands. The protocol module sends the string pointed
to by the extern char *cmarg to the remote as a Kermit generic server
command. The command string is of the format:
<cmd>[%<string1>...]\0
where <cmd> is a single upper-case letter representing the Kermit generic
command, and it is followed by one or more optional string arguments. Each
string is preceded by tochar() of its length. For example, the <cmd> for a
Kermit BYE (logout) command is L, and it takes no arguments, so the
simplest possible BYE subroutine would be:
void kermit_bye(void) {
static char bye_command[] = "L";
extern char *cmarg;
cmarg = &bye_command[0];
state = 'g';
proto();
}
See the Kermit book for a complete list of the generic commands and the
arguments required.
'c': Kermit REMOTE HOST command. cmarg points to a string in the remote's
command syntax which is to be executed by the remote, with output (if any)
from that command being returned by the remote server. Here is a simple
example:
#define tochar(c) ((c) + 32)
void kermit_remote_host(char *remote_command)
{
extern char *cmarg;
char command[90];
state = 'c';
cmarg = command;
cmarg[0] = tochar(strlen(remote_command));
strcpy(&cmarg[1], remote_command);
proto();
free(cmarg);
}
Notice that the string pointed to by cmarg must be small enough to fit in a
single Kermit packet; i.e., 90 characters or less.
External variables
There are several which are of interest to every user program. These
are, first of all, the flags parity, convert, and text. These are
simply checked against zero; a non-zero value means that parity is in
use (that is, the data path is 7 bits wide), that file names are to be
converted to a generic form, and that files are to be sent or received
as text, respectively. If they are zero, they indicate an 8-bit wide
data path, no file name conversion, and binary file transfer. These
are defined in kermitproto.w but must be declared in the user code;
that is, the declarations "int parity", "int convert", and "int text"
must appear somewhere outside of any block.
The value urpsiz must be declared by the user as well. This is a
mnemonic for "user requested packet size," and represents the size of
packets the user wants to request be used. I have written
kermitproto.w so that if urpsiz is such that long packets are
required, the code will also request type 3 (CRC) block checks, but
the equivalent of the SET BLOCK-CHECK 3 must be issued to the remote
as well.
The flags cx and cz can be used to abort a file transfer. If cx
is set upon return from ttinl(), the file currently being transferred
is skipped, and any partial result from the transfer is deleted. If
cz is set, then an entire batch transfer is aborted if one is in
progress. Most Kermit programs understand the protocol used for this
cancellation. Incidentally, the reason for these flags' names is that
the book recommends that Control-X be the cancel-file interrupt and
that Control-Z be the cancel-batch interrupt character.
Finally, there are all of the variables which control timeouts,
number of retries, block check type, and so on. These are described
in the comments at the beginning of the module.
Compiling This
kermitproto.w is a Wart file, and should be passed through the wart
preprocessor via the command:
wart kermitproto.w kermitproto.c
to generate a C file to hand to your local C compiler. wart is
available (as CKWART.C) from the Kermit archives in the usual way, and
is sufficiently portable so as to compile on a wide variety of systems
without modification.
Final Thoughts
32K is longer than I thought this module would end up when I started.
I hope it does save someone some work.